#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glpk.h>
#include "lib/ourlib.h"

int ia[1+1000], ja[1+1000],offset_coeff;
double ar[1+1000];

int generate_sep(glp_prob*,FILE*,int);

int main(int argc,char *argv[]) {
	/* Definizione delle strutture */
	glp_prob *lp;
	char* SEPARAZIONE_FILE = "separazione%d.lp";
	char buffer_str[128];
	char* SOLUZIONE_FILE = "soluzione";
	int i,n,e,z_index,sec_index;
	int i_array[2];
	double c_array[2];
	FILE* fp;
	double z;
	
	fp = fopen(SOLUZIONE_FILE, "r");
	// TODO controlli fp == null
	fscanf(fp,"%d %d %lf\n",&n,&e,&z); // la prima riga contiene numero di nodi e archi del grafo associato a questa soluzione
	rewind(fp);
	
	if(argc > 1){
		z_index = atoi(argv[1]);
		if(z_index > n) z_index = 1;
	}else{
		z_index = 1;
	}
	
	// Creazione del problema in memoria e assegnazione di un nome mnemonico
	lp = glp_create_prob();
	glp_set_prob_name(lp, "Problema separazione");
	
	sec_index = generate_sep(lp,fp,z_index);
	glp_load_matrix(lp, offset_coeff-1, ia, ja, ar);
	
	for(i = 1; i <= n; i++){
		i_array[1] = i;
		c_array[1] = 1;
		glp_set_mat_row(lp,sec_index,1,i_array,c_array);
		sprintf(buffer_str,SEPARAZIONE_FILE,i);
		glp_write_lp(lp, NULL, buffer_str);
	}
	
	
	glp_delete_prob(lp);
	printf ("%d\n",sec_index);
	return 0;
	
}

int generate_sep(glp_prob* lp, FILE* fp, int v){
	int i,n,e,v1,v2,offset_constr,z_index;
	double x,z;
	char varname[15], aux[5],constraintname[15];

	// Inizializzazione variabili
	strcpy(varname, "z_");
	strcpy(aux, "");
	strcpy(constraintname, "");

	// Tipologia del problema
	glp_set_obj_dir(lp, GLP_MAX);

	fscanf(fp,"%d %d %lf\n",&n,&e,&z); // la prima riga contiene numero di nodi e archi del grafo associato a questa soluzione

	z_index = n;
	if(z_index > n) return -1;

	// Aggiunta delle righe del problema (una coppia per arco più uno)
	glp_add_rows(lp, (2*e)+1);	
	// Aggiunta delle colonne del problema (una per arco più una per nodo)
	glp_add_cols(lp, n+e);

	for(i = 1; i <=n; i++){
		// qui possiamo generare le variabili z_i
		itoa(i, aux);
		strcat(varname, aux);
		glp_set_col_name(lp, i, varname);
		glp_set_col_bnds(lp, i, GLP_DB, 0.0, 1.0);

		// qui possiamo aggiungere in f.o. -z_i
		glp_set_obj_coef(lp, i, -1.0);
		
		strcpy(varname, "z_");
	}
	
	strcpy(varname, "w_");
	offset_coeff = 1;	// numero ordinale di coefficiente che stiamo inserendo (parte dal primo)
	offset_constr = 1;	// numero ordinale del vincolo che stiamo inserendo (parte dal primo)
	// Lettura righe
	for (i = 1; i <= e ; i++){
		// le righe successive contengono le variabili nella notazione "coda testa valore_sol"
		fscanf(fp,"%d %d %lf\n",&v1,&v2,&x); 		
		// in questa riga varname == "w_"
		itoa(v1, aux);
		strcat(varname, aux);
		// in questa riga varname == "w_v1"
		strcat(varname, "_");
		// in questa riga varname == "w_v1_"
		itoa(v2, aux);
		strcat(varname, aux);
		// in questa riga varname == "w_v1_v2"
		
		//	a questo punto possiamo generare la variabile w_v1_v2		
		glp_set_col_name(lp, n+i, varname);  // n+i esima perchè abbiamo creato n variabili z_i
		glp_set_col_bnds(lp, n+i, GLP_DB, 0.0, 1.0);
		//	a questo punto possiamo generare il vincolo w_v1_v2 - z_v1 <= 0
		ia[offset_coeff] = offset_constr;
		ja[offset_coeff] = n+i;	// w_v1_v2 è la n+i esima variabile
		ar[offset_coeff] = 1.0;
		offset_coeff++;	//abbiamo inserito un coefficiente della matrice
		
		ia[offset_coeff] = offset_constr;
		ja[offset_coeff] = v1; // z_v1 è la v1 esima variabile perchè sono state create in ordine
		ar[offset_coeff] = -1.0;
		offset_coeff++; //abbiamo inserito un coefficiente della matrice
		
		strcpy(constraintname,varname);
		strcat(constraintname,"-1");
		glp_set_row_name(lp, offset_constr, constraintname);
		glp_set_row_bnds(lp, offset_constr, GLP_UP, 0.0, 0.0);	// <= 0
		offset_constr++;	//abbiamo inserito un constraint
		
		//	a questo punto possiamo generare il vincolo w_v1_v2 - z_v2 <= 0
		ia[offset_coeff] = offset_constr;
		ja[offset_coeff] = n+i;	// w_v1_v2 è la n+i esima variabile
		ar[offset_coeff] = 1.0;
		offset_coeff++;	//abbiamo inserito un coefficiente della matrice
		
		ia[offset_coeff] = offset_constr;
		ja[offset_coeff] = v2; // z_v2 è la v2 esima variabile perchè sono state create in ordine
		ar[offset_coeff] = -1.0;
		offset_coeff++; //abbiamo inserito un coefficiente della matrice
		
		strcpy(constraintname,varname);
		strcat(constraintname,"-2");
		glp_set_row_name(lp, offset_constr, constraintname);
		glp_set_row_bnds(lp, offset_constr, GLP_UP, 0.0, 0.0);	// <= 0
		offset_constr++;	//abbiamo inserito un constraint
		
		//	a questo punto possiamo aggiungere in f.o. x * w_v1_v2
		glp_set_obj_coef(lp, n+i, x);
		
		strcpy(varname,"w_");
	}
	
	// qui possiamo generare il vincolo z_i = 1
	
	ia[offset_coeff] = offset_constr;
	ja[offset_coeff] = v; 
	ar[offset_coeff] = 1.0;
	offset_coeff++; //abbiamo inserito un coefficiente della matrice
	
	strcpy(constraintname,"Cerca subtour contenente z_i");
	glp_set_row_name(lp, offset_constr, constraintname);
	glp_set_row_bnds(lp, offset_constr, GLP_FX, 1.0, 1.0);	// <= 0
	
	fclose(fp);

	return offset_constr;
}

